package trophy

import (
	"fmt"

	"gddgame.cc/galaxy/common/service/lobby"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/serialize/msgpack"
)

// 匹配机制：主要是通过奖杯数去匹配对手的，对战胜利的玩家将赢得失利玩家损失的奖杯数，在正常情况下，游戏会优先匹配杯数相差100以内的玩家进行对战。如果没有匹配的，则顺延选择相差较小的玩家进行对战。
// 如何防止刷分？
// 1v1由于需要的玩家数量较小（2名），就造成了刷分门槛低的情况。supercell的规则是：两个账号在完成与其他至少三名玩家对战之前，是无法相互匹配到的。这也就强制了你必须通过对战才能够涨杯数。

type one struct {
	def.Serialize
}
type oneComputer struct {
	buckets []*bucketWrap
	history map[string][]string
}
type bucketWrap struct {
	min     int
	max     int
	buckets []*bucket
}
type bucket struct {
	min    int
	max    int
	client *lobby.Client
}

func (computer *oneComputer) init() {
	computer.buckets = make([]*bucketWrap, 0)
	computer.history = make(map[string][]string)
}

func (computer *oneComputer) Refresh(q *lobby.Queue) ([]*lobby.Client, map[string]interface{}) {
	computer.init()
	index := 0
	for e := q.Clients.Front(); e != nil; e = e.Next() {
		clients, c := computer.Add(e.Value.(*lobby.Client), index)
		if clients != nil {
			return clients, c
		}
		index++
	}
	return nil, nil
}

func (computer *oneComputer) Add(client *lobby.Client, index int) ([]*lobby.Client, map[string]interface{}) {
	//fmt.Printf("%#v\n", client.Users)
	level := 0
	for _, value := range client.Users {
		level += utils.ToInt(value)
	}
	scope := utils.ToInt(client.Options["scope"])
	min := level - scope
	max := level + scope

	lastIndex := -1
	minDiff := 0
	for index, wrap := range computer.buckets {
		if max < wrap.min || min > wrap.max {
			continue
		}
		md := wrap.min - min + wrap.max - max
		if md < minDiff || minDiff == 0 {
			minDiff = md
			lastIndex = index
		}
		for _, bucket := range wrap.buckets {
			if bucket.max < level || bucket.min > level {
				continue
			}
			return []*lobby.Client{bucket.client}, bucket.client.Options
		}
	}
	if lastIndex == -1 {
		computer.buckets = append(computer.buckets, &bucketWrap{
			min: min,
			max: max,
			buckets: []*bucket{&bucket{
				min:    min,
				max:    max,
				client: client,
			}},
		})
	} else {
		wrap := computer.buckets[lastIndex]
		wrap.buckets = append(wrap.buckets, &bucket{
			min:    min,
			max:    max,
			client: client,
		})
		if wrap.max < max {
			wrap.max = max
		}
		if wrap.min > min {
			wrap.min = min
		}
	}
	return nil, nil
}

func (computer *oneComputer) Timeout() ([]*lobby.Client, map[string]interface{}) {
	// 1v1，超时也没有方法开始
	return nil, nil
}

var (
	Default *one
)

func init() {
	Default = &one{
		Serialize: msgpack.Msgpack(true),
	}
}

func (p *one) ID() string {
	return "one"
}

func (p *one) GetComputer(channel string) lobby.Computer {
	return &oneComputer{}
}

func (p *one) Channel(users map[string]string, options map[string]interface{}) (string, []byte, error) {
	mode := options["mode"]
	if mode == nil {
		return "", nil, fmt.Errorf("Empty options:level")
	}

	scope := options["scope"]
	if scope == nil {
		return "", nil, fmt.Errorf("Empty options:scope")
	}

	channel := utils.ToString(mode)
	payload, err := p.Serialize.Marshal(options)
	return channel, payload, err
}
func (p *one) Parse(channel string, payload []byte) map[string]interface{} {
	data := make(map[string]interface{})
	_ = p.Serialize.Unmarshal(payload, &data)
	return data
}
func (p *one) Need(users map[string]string, options map[string]interface{}) bool {
	return false
}
